"use strict";

import {Native} from "./native.js";

/**
 * UDP接收数据格式枚举
 * @enum string
 * @readonly
 */
const TcpDataFormat = {
    TEXT: "text",
    HEX: "hexString"
};


/**
 * Tcp客户端
 * @version 2
 * @author GuoHua Liu
 * @copyright Copyright © 2019 GuoHua Liu. All rights reserved.
 * @example
 import {TcpClient, TcpDataFormat} from './tcp.js'
 //...
 */
class TcpClient {
    /**
     * @private
     * @param {string} name
     * @param {function} onevent
     * @param {*} context
     */
    addObserver(name, onevent, context) {
        if (this.socket > 0) {
            Native.getInstance().addObserver("tcp/" + this.socket + "/" + name, onevent, context);
        }
        return this;
    }

    /**
     * @private
     * @param {string} name
     * @param {function} onevent
     */
    removeObserver(name, onevent) {
        if (this.socket > 0) {
            Native.getInstance().delObserver("tcp/" + this.socket + "/" + name, onevent);
        }
        return this;
    }

    /**
     * @callback TcpRecvObserver
     * @param {{name:string,data:{data:string}}} event
     */

    /**
     * 添加观察者：接收TCP包
     * @since 2
     * @param {TcpRecvObserver} onevent
     * @param {*} context
     */
    addRecvObserver(onevent, context=null) {
        this.addObserver("recv", onevent, context);
        return this;
    }

    /**
     * 删除addRecvObserver注册的观察者
     * @since 2
     * @param {TcpRecvObserver|null} onevent
     */
    removeRecvObserver(onevent = null) {
        this.removeObserver("recv", onevent);
        return this;
    }

    /**
     * @callback TcpDisconnectObserver
     * @param {{name:string}} event
     */

    /**
     * 添加观察者：监听断连事件
     * @since 2
     * @param {TcpDisconnectObserver} onevent
     * @param {*} context
     */
    addDisconnectObserver(onevent, context=null) {
        this.addObserver("disconnect", onevent, context);
        return this;
    }

    /**
     * 删除addDisconnectObserver注册的观察者
     * @since 2
     * @param {TcpDisconnectObserver|null} onevent
     */
    removeDisconnectObserver(onevent = null) {
        this.removeObserver("disconnect", onevent);
        return this;
    }

    /**
     * 移除所有的观察者
     * @since 2
     */
    removeAllObserver() {
        this.removeRecvObserver();
        this.removeDisconnectObserver();
    }

    /**
     * 发起连接
     * @since 2
     * @returns {Promise} 成功回调无参数;失败回调携带`{errMsg,errCode}`格式参数，其中errCode可能是:
     * - 1 未成功创建socket
     * - 2 连接服务器失败
     * - 其他 未知错误
     */
    connect() {
        return new Promise((resolve,reject)=>{
            if (this.socket <= 0) {
                reject({errMsg: "socket资源不足",errCode: 1});
                return;
            }
            if (!this.serverHost || !this.serverPort || !this.recvDataFormat) {
                reject({errMsg: "参数错误", errCode: 3});
                return;
            }
            Native.getInstance().callNative("tcp", {
                "method": "connect",
                "socket": this.socket,
                "serverHost": this.serverHost,
                "serverPort": this.serverPort,
                "recvDataFormat": this.recvDataFormat
            }, true, ()=>{
                resolve();
            }, (error)=>{
                reject(error);
            });
        });
    }

    /**
     * 发送数据
     * @since 2
     * @param {string} sendData 需要发送的数据，需为hexString格式
     * @param {TcpDataFormat} sendDataFormat 可以是
     * - {@link TcpDataFormat.HEX} hex string
     * - {@link TcpDataFormat.TEXT} utf-8编码字符串
     * @returns {Promise} 成功回调无参数;失败回调携带`{errMsg,errCode}`格式参数，其中errCode可能是:
     * - 1 socket已经关闭
     * - 2 无效数据
     * - 3 发送数据失败
     * - 其他 未知错误
     */
    send(sendData, sendDataFormat = TcpDataFormat.HEX) {
        return new Promise((resolve,reject)=>{
            if (this.socket <= 0) {
                reject({errMsg: "未成功创建通讯", errCode: 1});
                return;
            }
            Native.getInstance().callNative("tcp",
                {method: "send", data: sendData, socket: this.socket, dataFormat: sendDataFormat},
                true,
                (result)=>resolve(result), (error)=>reject(error));
        });
    }

    /**
     * 构建Tcp客户端
     * @since 2
     * @param {string} serverHost
     * @param {number} serverPort
     * @param {TcpDataFormat} recvDataFormat since 3, 可以是
     * - {@link TcpDataFormat.HEX} 接收到的数据(UdpRecvEventData#data)为hexString
     * - {@link TcpDataFormat.TEXT} 接收到的数据(UdpRecvEventData#data)为文本(utf-8编码)
     */
    constructor(serverHost, serverPort, recvDataFormat = TcpDataFormat.HEX) {
        this.serverHost = serverHost;
        this.serverPort = serverPort;
        this.recvDataFormat = recvDataFormat;
        this.socket = Native.getInstance().syncCallNative("tcp", {method: "socket"}).socket;
        if (this.socket <= 0) {
            alert("创建Tcp通讯失败");
        }
    }

    /**
     * 任何情况下，不使用的时候就要调用destroy释放资源。
     * @since 2
     */
    destroy() {
        if (this.socket > 0) {
            this.removeAllObserver();
            Native.getInstance().syncCallNative("tcp", {method: "close", socket: this.socket});
            this.socket = 0;
        }
    }
}



export {TcpClient, TcpDataFormat};



